Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move NotebookControllerManager into the DI container for web #9690

Merged
merged 9 commits into from
Apr 15, 2022

Conversation

rchiodo
Copy link
Contributor

@rchiodo rchiodo commented Apr 14, 2022

Fixes #9662

@rchiodo rchiodo requested a review from a team as a code owner April 14, 2022 22:30
@@ -32,23 +32,6 @@ const config = {
},
module: {
rules: [
{
// JupyterServices imports node-fetch.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As soon as I started importing these into the web bundle, this code failed to work.

I believe we don't need in the webbundle anymore.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not seeing the node-fetch usage anymore in jupyterlab services.

@@ -16,4 +21,15 @@ export function registerTypes(serviceManager: IServiceManager, _isDevMode: boole
IExtensionSingleActivationService,
PythonKernelCompletionProviderRegistration
);
serviceManager.addSingleton<IExtensionSyncActivationService>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved a bunch of stuff here from the 'notebooks' serviceRegistry. Seemed weird that notebooks would register stuff from the intellisense folder.

@@ -186,7 +173,7 @@ export class InteractiveWindow implements IInteractiveWindowLoadable {
};
// When connecting, we need to update the sys info message
this.updateSysInfoMessage(this.getSysInfoMessage(metadata, SysInfoReason.Start), false, sysInfoCell);
const kernel = await connectToKernel(
const kernel = await KernelConnector.connectToKernel(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved all the loose functions for connecting to a kernel into a new static class - KernelConnector.

* Keep track of the fact that we attempted to install a package into an interpreter.
* (don't care whether it was successful or not).
*/
export async function trackPackageInstalledIntoInterpreter(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These loose functions didn't have any .node dependencies but were used elsewhere so moved them into a separate file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes those are helpers.ts? Or does that note fit here?

}

this.scriptProviders = scriptProviders;
// Use the platform specific factory to get our providers
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to make this class platform agnostic, the creation of the script providers was moved to a platform specific factory.

The web version only support remote right now, but we might be able to do something about loading it from the CDN later.

@inject(IPythonExecutionFactory) private readonly factory: IPythonExecutionFactory
) {}

public getProviders(kernel: IKernel, uriConverter: ILocalResourceUriConverter, httpClient: IHttpClient) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function used to be in ipyWidgetScriptSourceProvider.ts. This is the node version.

@codecov-commenter
Copy link

codecov-commenter commented Apr 14, 2022

Codecov Report

Merging #9690 (49adb87) into main (ecc0aaf) will increase coverage by 0%.
The diff coverage is 77%.

❗ Current head 49adb87 differs from pull request most recent head bd0382a. Consider uploading reports for the commit bd0382a to get more accurate results

@@         Coverage Diff          @@
##           main   #9690   +/-   ##
====================================
  Coverage    63%     63%           
====================================
  Files       201     204    +3     
  Lines      9826    9837   +11     
  Branches   1557    1556    -1     
====================================
+ Hits       6230    6245   +15     
+ Misses     3097    3091    -6     
- Partials    499     501    +2     
Impacted Files Coverage Δ
src/platform/api/apiAccessService.ts 44% <ø> (ø)
src/platform/common/application/clipboard.ts 42% <ø> (ø)
src/platform/common/application/documentManager.ts 82% <ø> (ø)
...rc/platform/common/application/encryptedStorage.ts 44% <ø> (ø)
src/platform/common/application/notebook.ts 87% <ø> (ø)
src/platform/common/asyncDisposableRegistry.ts 75% <ø> (ø)
src/platform/common/platform/types.ts 100% <ø> (ø)
src/platform/common/utils/multiStepInput.ts 75% <ø> (ø)
src/platform/common/utils/regexp.ts 66% <ø> (ø)
.../platform/common/variables/systemVariables.node.ts 39% <0%> (ø)
... and 52 more

@injectable()
export class ScriptSourceProviderFactory implements IWidgetScriptSourceProviderFactory {
public getProviders(kernel: IKernel, _uriConverter: ILocalResourceUriConverter, httpClient: IHttpClient) {
const scriptProviders: IWidgetScriptSourceProvider[] = [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THis is the web version of the same function.

const sanitize = require('sanitize-filename');

@injectable()
export class ScriptUriConverter implements ILocalResourceUriConverter {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also had to separate out the URI converter part from the ipyWidgetScriptSource because it has node specific stuff in it too (reading/writing to local disk)

_connInfo: INotebookProviderConnection | undefined
): Promise<KernelConnectionMetadata[]> {
sendKernelListTelemetry(resource, []);
return [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will likely be the same as the node version once I get all of the session classes below this to work. For now there are two so I can stop this PR at this point.

// Instead there will be a IKernelFinder for web and an IKernelFinder for node. It will coalesce the local/remote bits.
// But for now, it was simpler to just make this kernel finder that returns nothing.
@injectable()
export class LocalKernelFinder implements ILocalKernelFinder {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class should be temporary. The reason this exists is because the NotebookControllerManager is doing special logic for local.

I hope to remove this entirely in a IKernelFinder implementation later.

import { getDisplayPath } from '../platform/common/platform/fs-paths';
import { IPythonExecutionFactory } from '../platform/common/process/types.node';
import {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this file moved to helpers.ts. Only the 'node' specific stuff remained here.

import { SilentExecutionErrorOptions } from './helpers';
import { originalFSPath } from '../platform/vscode-path/resources';

export abstract class BaseKernel implements IKernel {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created this as the common parts of the IKernel implementation.

configService,
workspaceService,
cellHashProviderFactory
);
this.kernelExecution = new KernelExecution(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KernelExecution is node specific at the moment, so chopped off this work at this point.

When I get to implementing the kernel for web, KernelExecution will likely be the starting point.

/**
* Class used for connecting a controller to an instance of an IKernel
*/
export class KernelConnector {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all the functions that used to be in helper.ts for connecting to a kernel. There was even a little bit of state. Figured it made sense to put the functions into a class to hold the state.

import { noop } from '../platform/common/utils/misc';
import { IKernel, IKernelProvider, KernelOptions } from './types';

export abstract class BaseKernelProvider implements IKernelProvider {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KernelProvider creates the Kernel class directly so I had to split it into two parts as well. This is the base class for them both.

this._onDidDisposeKernel.dispose();
this._onDidRestartKernel.dispose();
this._onKernelStatusChanged.dispose();
}
public getOrCreate(uri: Uri, options: KernelOptions): IKernel {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only function that's specific to each version.

import { INotebookControllerManager } from '../types';

@injectable()
export class CondaControllerRefresher implements IExtensionSingleActivationService {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file exists because the NotebookControllerManager used to listen to the conda service in order to refresh its list of controllers.

Conda Service is node only, so I created this one off to accomplish the same thing.

import { ConsoleForegroundColors, TraceOptions } from '../../platform/logging/types';
import { KernelConnector } from '../../kernels/kernelConnector';

export class VSCodeNotebookController implements Disposable {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was the reason for this PR. And just getting this to build caused all of these other changes :)

import { IInteractiveWindowProvider, IInteractiveWindow } from './types';

export type InteractiveCellMetadata = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a src/interactive-window/types.ts maybe put the type into that?

import { fsPathToUri } from '../../vscode-path/utils';
import { EnvironmentVariables } from '../variables/types';
import { getOSType, OSType } from './platform';
export * from './platform';

// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
const untildify = require('untildify');
const homePath = untildify('~');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was kinda redundant. Untilidify uses the homedir to replace ~.

@@ -22,3 +22,7 @@ export function getOSType(platform: string = process.platform): OSType {
return OSType.Unknown;
}
}

export function untildify(path: string, home: string) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the platform neutral version.

import { injectable } from 'inversify';
import { traceError } from '../logging';
import { ICryptoUtils, IHashFormat } from './types';
import * as hashjs from 'hash.js';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a secure hash for this stuff, we just use it to create names of files.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plus crypto is deprecated I think.

import { PythonEnvironment } from '.';
import { getOSType, OSType } from '../../common/utils/platform';

export function getInterpreterHash(interpreter: PythonEnvironment | {uri: Uri}){
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these functions could be used in both .node and .web.

import { compare as strCompare, equalsIgnoreCase } from './strings';
import { Schemas } from './utils';

function originalFSPath(uri: URI): string {
return uri.fsPath;
export function originalFSPath(uri: URI | undefined): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might not have payed enough attention to where this was used, but the name seems a bit off now. A .path property for a web URI isn't an fspath.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually looking at the usage I think this works. NVMD

@rchiodo rchiodo merged commit 261afd9 into main Apr 15, 2022
@rchiodo rchiodo deleted the rchiodo/notebook_controller_web branch April 15, 2022 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Get NotebookController able to run in the web extension
3 participants